package com.fengye.lock.db.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fengye.lock.db.domain.UserAccount;
import com.fengye.lock.db.domain.UserAccountRecord;
import com.fengye.lock.db.dto.UserAccountDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;

/**
 *
 * @author sky
 * @date 2021年06月11日 10:39 上午
 */
@Service
@Slf4j
public class DatabaseLockService {

    @Autowired
    UserAccountService userAccountService;

    @Autowired
    UserAccountRecordService userAccountRecordService;

    public void takeMoney(UserAccountDTO dto) throws Exception {
        // 获取用户账户实体记录
        QueryWrapper<UserAccount> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", dto.getUserId());
        UserAccount userAccount = userAccountService.getOne(wrapper);


        // 用户账户是否存在，并且账户余额是否够提现
        if (userAccount != null && userAccount.getAmount().doubleValue() - dto.getAmount() > 0) {

            // 更新用户账户的余额
            userAccountService.updateAmountById(dto.getAmount(), userAccount.getId());

            log.info("提现成功，提现金额为：{},账户余额为:{}", dto.getAmount(), userAccount.getAmount());

            // 插入一条用户更新的记录
            UserAccountRecord userAccountRecord = new UserAccountRecord();
            userAccountRecord.setCreateTime(new Date());
            userAccountRecord.setAccountId(userAccount.getId());
            userAccountRecord.setMoney(BigDecimal.valueOf(dto.getAmount()));

            userAccountRecordService.save(userAccountRecord);

            // log.info("提现完成，并记录成功, {}", userAccountRecord);
        } else {
            throw new Exception("账户不存在或账户余额不足");
        }
    }

    /**
     * 乐观锁方式更新
     * @param dto {@link UserAccountDTO}
     */
    public void takeMoneyWithVersion(UserAccountDTO dto) throws Exception {
        // 获取用户账户实体记录
        QueryWrapper<UserAccount> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", dto.getUserId());
        // 查询结果带有 version 字段（乐观锁）
        UserAccount userAccount = userAccountService.getOne(wrapper);


        // 用户账户是否存在，并且账户余额是否够提现
        if (userAccount != null && userAccount.getAmount().doubleValue() - dto.getAmount() > 0) {

            // 更新用户账户的余额
            int res = userAccountService.updateAmountByIdAndVersion(dto.getAmount(), userAccount.getId(), userAccount.getVersion());
            if (res > 0) {
                log.info("【乐观锁方式】提现成功，提现金额为：{},账户余额为:{}", dto.getAmount(), userAccount.getAmount());

                // 更新用户账户余额变动情况到数据库
                UserAccountRecord userAccountRecord = new UserAccountRecord();
                userAccountRecord.setCreateTime(new Date());
                userAccountRecord.setAccountId(userAccount.getId());
                userAccountRecord.setMoney(BigDecimal.valueOf(dto.getAmount()));

                userAccountRecordService.save(userAccountRecord);

                // log.info("提现完成，并记录成功, {}", userAccountRecord);
            } else {
                log.error("提现失败，账户不存在或账户余额不足");
            }

        } else {
            throw new Exception("账户不存在或账户余额不足");
        }
    }

    /**
     * 悲观锁方式更新用户账户(for update）
     * @param dto {@link UserAccountDTO}
     */
    public void takeMoneyWithNegativeLock(UserAccountDTO dto) throws Exception {
        // 获取用户账户实体记录(for update）
        UserAccount userAccount = userAccountService.selectByUserIdLock(dto.getUserId());

        // 用户账户是否存在，并且账户余额是否够提现
        if (userAccount != null && userAccount.getAmount().doubleValue() - dto.getAmount() > 0) {

            // 更新用户账户的余额
            int res = userAccountService.updateAmountLock(dto.getAmount(), userAccount.getId());
            if (res > 0) {

                // 插入一条用户更新的记录
                UserAccountRecord userAccountRecord = new UserAccountRecord();
                userAccountRecord.setCreateTime(new Date());
                userAccountRecord.setAccountId(userAccount.getId());
                userAccountRecord.setMoney(BigDecimal.valueOf(dto.getAmount()));

                userAccountRecordService.save(userAccountRecord);

                log.info("【悲观锁方式】提现成功，提现金额为：{},账户余额为:{}", dto.getAmount(), userAccount.getAmount());
                // log.info("提现完成，并记录成功, {}", userAccountRecord);
            } else {
                log.error("提现失败，账户不存在或账户余额不足");
            }

        } else {
            throw new Exception("账户不存在或账户余额不足");
        }
    }
}
